package com.infolab.aims.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.infolab.aims.common.InQueryHelper;
import com.infolab.aims.common.PaginationHelper;
import com.infolab.aims.common.QueryHelper;
import com.infolab.aims.common.bean.SearchCriteria;
import com.infolab.aims.common.bean.SearchResult;
import com.infolab.aims.domain.Audit;
import com.infolab.aims.service.intf.AuditService;

@Service
@Transactional
public class AuditServiceImpl implements AuditService {

	Log logger = LogFactory.getLog(getClass());
	@PersistenceContext
	private EntityManager em;

	public void createAudit(Audit audit) {

		Audit newAudit = new Audit();

		audit.setModifiedBy(audit.getCreatedBy());
		audit.setDateCreated(new Date());
		audit.setDateModified(new Date());

		BeanUtils.copyProperties(audit, newAudit);

		em.persist(newAudit);

		audit.setAuditId(newAudit.getAuditId());

	}

	public Audit getAudit(Long auditId) {

		return em.find(Audit.class, auditId);
	}

	public Audit findAudit(SearchCriteria searchCriteria) {
		
		String jpql = 
			"from Audit " +
			"where auditId = (" +
			"   select max(auditId) from Audit where auditCode in (" +
			"            select auditCode from Audit where auditId = ? " +
			"   ) and auditId < ?" +
			")";

		Long auditId = (Long)searchCriteria.getSearchCriteria("auditId");
		Query query = em.createQuery(jpql);
		query.setParameter(1, auditId);
		query.setParameter(2, auditId);
		List<Audit> list = query.getResultList();
		if(CollectionUtils.isNotEmpty(list)){
			return list.get(0);
		}
		return null;
	}

	public List<Audit> searchAuditCriteria(SearchCriteria searchCriteria) {

		if (searchCriteria == null)
			searchCriteria = new SearchCriteria();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Audit> cq = cb.createQuery(Audit.class);

		Root<Audit> root = cq.from(Audit.class);
		List<Predicate> criteria = new ArrayList<Predicate>();

		if (searchCriteria.getSearchCriteria("active") != null) {
			ParameterExpression<Boolean> p = cb.parameter(Boolean.class, "active");
			criteria.add(cb.equal(root.get("active"), p));
		}

		if (searchCriteria.getSearchCriteria("auditCode") != null) {

			Object obj = searchCriteria.getSearchCriteria("auditCode");
			if (obj instanceof InQueryHelper) {
				ParameterExpression<List> p = cb.parameter(List.class, "auditCode");
				criteria.add(cb.in(root.get("auditCode")).value(p));
			}else{
				ParameterExpression<String> p = cb.parameter(String.class, "auditCode");
				criteria.add(cb.equal(root.get("auditCode"), p));
			}
		}

		cq.select(root);

		if (criteria.size() == 0) {
		} else if (criteria.size() == 1) {
			cq.where(criteria.get(0));
		} else {
			cq.where(cb.and(criteria.toArray(new Predicate[0])));
		}

		Query query = em.createQuery(cq);

		if (searchCriteria.getSearchCriteria("active") != null) {
			boolean tmp = (Boolean) searchCriteria.getSearchCriteria("active");
			query.setParameter("active", tmp);
		}

		if (searchCriteria.getSearchCriteria("auditCode") != null) {
			Object obj = searchCriteria.getSearchCriteria("auditCode");
			if (obj instanceof InQueryHelper) {
				query.setParameter("auditCode", ((InQueryHelper) obj).getColumnValues());
			}else{
				query.setParameter("auditCode", (String)searchCriteria.getSearchCriteria("auditCode"));
			}
		}

		if (searchCriteria.getMaxRow() != null)
			query.setMaxResults(searchCriteria.getMaxRow());

		return query.getResultList();

	}

	public SearchResult searchAudit(SearchCriteria searchCriteria) {
		AuditPaginationHelper helper = new AuditPaginationHelper();

		return helper.getSearchResultFromQueryHelper(em, searchCriteria);
	}

	public void deleteAudit(Integer auditId) {

		Query query = em.createQuery("update Audit set active=0 where auditId=:auditId");

		query.setParameter("auditId", auditId);

		query.executeUpdate();

	}

	public static class AuditPaginationHelper extends PaginationHelper<Audit> {

		@Override
		public String[] getValidColumnName() {
			return new String[] { "auditId", "moduleName", "operation", "dateModified",  "contentHead", "contentDetail" };
		}

		@Override
		public String[] getValidSortName() {
			return new String[] { "auditId", "moduleName", "operation",  "contentHead", "contentDetail", "modifiedBy", "dateModified" };
		}

		@Override
		public String getDefaultSortName() {
			return "auditId desc";
		}

		@Override
		public QueryHelper getQueryHelper() {
			QueryHelper queryHelper = new QueryHelper();
			queryHelper.select("select audit from Audit audit");
			return queryHelper;
		}
	}

	public SearchResult searchAduit(SearchCriteria searchCriteria) {
		AuditPaginationHelper helper = new AuditPaginationHelper();
		if(searchCriteria.getCurPage()==null)
			searchCriteria.setCurPage(1);
		return helper.getSearchResultFromQueryHelper(em, searchCriteria);
	}

	public void deleteAduit(Long auditId) {

		Query query = em.createQuery("delete Audit where auditId=:auditId");

		query.setParameter("auditId", auditId);

		query.executeUpdate();
	}

}
